<?php

namespace app\api\controller;

use app\common\traits\ApiTrait;
use Psr\Http\Message\ResponseInterface;
use support\Request;
use support\Response;
use think\facade\Db;
use Tinywan\Jwt\JwtToken;
use Yansongda\Pay\Pay;
use support\Log;

class OrderController
{
    use ApiTrait;

    /**
     * 不需要登录的方法
     */
    protected $noNeedLogin = ['notify', 'batchesNotify', 'refund'];

    /**
     * 支付
     * @param Request $request
     * @return Response
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function payment(Request $request): Response
    {
        if (!request()->isPost()) {
            return $this->reError('请求方式错误');
        }

        try {
            $activityId = $request->post('activityId');
            if (empty($activityId)) {
                return $this->reError('参数错误');
            }

            $paymentInfo = Db::name('order')
                ->alias('order')
                ->join('user', 'order.user_id = user.id')
                ->join('activity', 'order.activity_id = activity.id')
                ->join('payment_account account', 'activity.activity_payment_id = account.id')
                ->field('order.id as order_id, order.order_sn, order.total_price, order.pay_no, activity.activity_title, activity.activity_present_price')
                ->field('user.openid, account.mchid, account.appsecret, account.pemcert, account.pemkey, account.public_cert, account.public_cert_id')
                ->where(['order.user_id' => JwtToken::getExtend()['id'], 'order.activity_id' => $activityId])
                ->find();

            $paymentInfo['total_price'] = $paymentInfo['activity_present_price'];
            $paymentInfo['pay_no'] = date('YmdHis').strtoupper(randomkeys(10));
            Db::name('order')->where(['user_id' => JwtToken::getExtend()['id'], 'activity_id' => $activityId])->update([
                'order_status' => 1,
                'pay_no' => $paymentInfo['pay_no'],
                'total_price' => $paymentInfo['activity_present_price'],
                'create_time' => date('Y-m-d H:i:s'),
            ]);

            Pay::config([
                'wechat' => [
                    'default' => [
                        // 「必填」商户号，服务商模式下为服务商商户号
                        'mch_id' => $paymentInfo['mchid'],
                        // 「必填」v3 商户秘钥
                        'mch_secret_key' => $paymentInfo['appsecret'],
                        // 「必填」商户私钥 字符串或路径
                        'mch_secret_cert' => url2tempFile($paymentInfo['pemkey']),
                        // 「必填」商户公钥证书路径
                        'mch_public_cert_path' => url2tempFile($paymentInfo['pemcert']),
                        // 「选填」小程序 的 app_id
                        'mini_app_id' => sysconfig('wechat', 'miniapp_appid'),
                        // 「选填」（适用于 2024-11 及之前开通微信支付的老商户）微信平台公钥证书路径，强烈建议 php-fpm 模式下配置此参数
                        // 「必填」微信支付公钥证书路径，key 填写形如 PUB_KEY_ID_0000000000000024101100397200000006 的公钥id，见 https://pay.weixin.qq.com/doc/v3/merchant/4013053249
                        'wechat_public_cert_path' => [
                            $paymentInfo['public_cert_id'] => url2tempFile($paymentInfo['public_cert']),
                        ],
                    ]
                ],
                'logger' => [
                    'enable' => true,
                    'file' => base_path(false).'/runtime/logs/wxpay-request-'.date('Y-m-d').'.log',
                    'level' => 'info', // 建议生产环境等级调整为 info，开发环境为 debug
                    'type' => 'single', // optional, 可选 daily.
                    'max_file' => 30, // optional, 当 type 为 daily 时有效，默认 30 天
                ]
            ]);

            $res = Pay::wechat()->mini([
                'notify_url' => getenv('API_HOST').'/api/order/notify/'.$paymentInfo['order_sn'],
                'out_trade_no' => $paymentInfo['pay_no'],
                'description' => $paymentInfo['activity_title'],
                'amount' => [
                    'total' => $paymentInfo['total_price'] * 100
                ],
                'payer' => [
                    'openid' => $paymentInfo['openid']
                ],
                'attach' => json_encode(['order_sn' => $paymentInfo['order_sn']])
            ]);
            return $this->reSuccess('数据获取成功', $res);
        } catch (\Exception $error) {
            return $this->reError($error->response->message ?? $error->getMessage());
        }
    }

    /**
     * 支付回调
     * @param Request $request
     * @param $orderSN
     * @return Response
     * @throws \Yansongda\Artful\Exception\ContainerException
     * @throws \Yansongda\Artful\Exception\InvalidParamsException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function notify(Request $request, $orderSN)
    {
        $paymentInfo = Db::name('order')
            ->alias('order')
            ->join('user', 'order.user_id = user.id')
            ->join('activity', 'order.activity_id = activity.id')
            ->join('payment_account account', 'activity.activity_payment_id = account.id')
            ->field('user.openid, account.mchid, account.appsecret, account.pemcert, account.pemkey, account.public_cert, account.public_cert_id')
            ->field('order.id as order_id, order.activity_id')
            ->where(['order.order_sn' => $orderSN])
            ->find();

        Pay::config([
            'wechat' => [
                'default' => [
                    // 「必填」商户号，服务商模式下为服务商商户号
                    'mch_id' => $paymentInfo['mchid'],
                    // 「必填」v3 商户秘钥
                    'mch_secret_key' => $paymentInfo['appsecret'],
                    // 「必填」商户私钥 字符串或路径
                    'mch_secret_cert' => url2tempFile($paymentInfo['pemkey']),
                    // 「必填」商户公钥证书路径
                    'mch_public_cert_path' => url2tempFile($paymentInfo['pemcert']),
                    // 「选填」小程序 的 app_id
                    'mini_app_id' => sysconfig('wechat', 'miniapp_appid'),
                    // 「选填」（适用于 2024-11 及之前开通微信支付的老商户）微信平台公钥证书路径，强烈建议 php-fpm 模式下配置此参数
                    // 「必填」微信支付公钥证书路径，key 填写形如 PUB_KEY_ID_0000000000000024101100397200000006 的公钥id，见 https://pay.weixin.qq.com/doc/v3/merchant/4013053249
                    'wechat_public_cert_path' => [
                        $paymentInfo['public_cert_id'] => url2tempFile($paymentInfo['public_cert']),
                    ],
                ]
            ]
        ]);


        $result = Pay::wechat()->callback();

        Log::info('['.date('Y-m-d H:i:s').'] wxpay-notify');
        Log::info(json_encode($result, JSON_UNESCAPED_UNICODE));

        if ($result['event_type'] == 'TRANSACTION.SUCCESS') {
            // 校验订单号是否一致
            $attach = json_decode($result['resource']['ciphertext']['attach'], true);
            if ($orderSN == $attach['order_sn']) {
                // 增加活动参与量
                Db::name('activity')->where(['id' => $paymentInfo['activity_id']])->setInc('sales_num');
                // 修改订单状态
                Db::name('order')->where(['id' => $paymentInfo['order_id']])->update([
                    'order_status' => 2,
                    'pay_no' => $result['resource']['ciphertext']['out_trade_no'],
                    'pay_time' => date('Y-m-d H:i:s')
                ]);

                $activity = Db::name('activity')->where(['id' => $paymentInfo['activity_id']])->find();
                $order = Db::name('order')->where(['id' => $paymentInfo['order_id']])->find();
                $recom_user_role = Db::name('activity_user_role')->where(['user_id' => $order['recom_user_id'], 'activity_id' => $paymentInfo['activity_id']])->find();
                $visitor = Db::name('activity_visitor')->where(['activity_id' => $activity['id'], 'user_id' => $order['user_id']])->find();
                $platform_box = Db::name('platform_box')->where(['id' => $activity['platform_box_id']])->find();

                // 判断是否有推荐人
                if (!empty($order['recom_user_id'])) {
                    // 发放推荐奖励
                    // 根据活动设置，需要判断员工是否可以参与推荐奖励
                    if (!($recom_user_role == 1 && $activity['staff_is_recom'] == 0)) {
                        // 给推荐人增加翻牌抽奖次数
                        if ($activity['recom_payment_prize_plus_one'] == 1) {
                            Db::name('activity_visitor')->where(['activity_id' => $activity['id'], 'user_id' => $order['recom_user_id']])->setInc('activity_draw_num');
                        }
                        // 给推荐人发放推荐奖励
                        if (!empty($activity['recom_reward_amount'])) {
                            $disburse_sn = date('YmdHis').strtoupper(randomkeys(10));
                            try {
                                $this->batches($activity['id'], $order['user_id'], '推荐奖励', $disburse_sn,$activity['recom_reward_amount'] * 100, '奖励');
                            } catch (\Exception $error) {
                                $error_remark = $error->response->message ?? $error->getMessage();
                            }
                            // 写入支出明细
                            Db::name('payment_disburse')->insert([
                                'activity_id' => $activity['id'],
                                'order_id' => $order['id'],
                                'user_id' => $order['recom_user_id'],
                                'status' => empty($error_remark) ? 0 : 2,
                                'disburse_sn' => $disburse_sn,
                                'name' => '推荐奖励',
                                'amount' => $activity['recom_reward_amount'],
                                'remark' => empty($error_remark) ? '' : $error_remark,
                                'create_time' => date('Y-m-d H:i:s')
                            ]);
                        }
                    }
                    // 首次参与获得平台盲盒默认抽奖次数
                    if ($activity['platform_box_is_join'] == 1 && $visitor['platform_box_release_default'] == 0) {
                        Db::name('activity_visitor')->where(['activity_id' => $activity['id'], 'user_id' => $order['user_id']])->update([
                            'platform_box_draw_num' => $platform_box['default_num'],
                            'platform_box_release_default' => 1
                        ]);
                    }
                    // 平台盲盒推荐奖励
                    if ($activity['platform_box_is_join'] == 1) {
                        // 获取上级总推荐人数
                        $recom_num = Db::name('order')->where(['activity_id' => $paymentInfo['activity_id'], 'user_id' => $order['recom_user_id'], 'order_status' => 2])->count();
                        if (!empty($platform_box['recom_num']) && $recom_num > 0) {
                            // 通过倍数判断是否达到奖励标准
                            if ($recom_num % $platform_box['recom_num'] == 0) {
                                // 给推荐人发放盲盒抽奖次数
                                Db::name('activity_visitor')->where(['activity_id' => $activity['id'], 'user_id' => $order['recom_user_id']])->setInc('platform_box_draw_num', $platform_box['reward_num']);
                            }
                        }
                    }
                }

                // 将未领取的奖品变为已领取
                // 翻牌抽奖奖品
                Db::name('payment_activity_prize')->where([
                    'activity_id' => $activity['id'],
                    'user_id' => $order['user_id'],
                    'receive_status' => 0,
                    'status' => 0
                ])->update([
                    'receive_status' => 1,
                    'receive_time' => date('Y-m-d H:i:s')
                ]);
            }
        }
        return json(['code' => 'SUCCESS', 'message' => '成功']);
    }

    /**
     * 转账
     * @param $activity_id
     * @param $prize_sn
     * @param $transfer_amount
     * @param $transfer_remark
     * @return \Yansongda\Artful\Rocket|\Yansongda\Supports\Collection
     * @throws \Yansongda\Artful\Exception\ContainerException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function batches($activity_id, $user_id, $prize_name, $prize_sn, $transfer_amount, $transfer_remark)
    {
        $paymentInfo = Db::name('order')
            ->alias('order')
            ->join('user', 'order.user_id = user.id')
            ->join('activity', 'order.activity_id = activity.id')
            ->join('payment_account account', 'activity.recom_payment_id = account.id')
            ->field('user.openid, account.mchid, account.appsecret, account.pemcert, account.pemkey, account.public_cert, account.public_cert_id')
            ->field('order.order_sn, activity.activity_title')
            ->where(['order.activity_id' => $activity_id, 'order.user_id' => $user_id])
            ->find();

        Pay::config([
            'wechat' => [
                'default' => [
                    // 「必填」商户号，服务商模式下为服务商商户号
                    'mch_id' => $paymentInfo['mchid'],
                    // 「必填」v3 商户秘钥
                    'mch_secret_key' => $paymentInfo['appsecret'],
                    // 「必填」商户私钥 字符串或路径
                    'mch_secret_cert' => url2tempFile($paymentInfo['pemkey']),
                    // 「必填」商户公钥证书路径
                    'mch_public_cert_path' => url2tempFile($paymentInfo['pemcert']),
                    // 「选填」小程序 的 app_id
                    'mini_app_id' => sysconfig('wechat', 'miniapp_appid'),
                    // 「选填」（适用于 2024-11 及之前开通微信支付的老商户）微信平台公钥证书路径，强烈建议 php-fpm 模式下配置此参数
                    // 「必填」微信支付公钥证书路径，key 填写形如 PUB_KEY_ID_0000000000000024101100397200000006 的公钥id，见 https://pay.weixin.qq.com/doc/v3/merchant/4013053249
                    'wechat_public_cert_path' => [
                        $paymentInfo['public_cert_id'] => url2tempFile($paymentInfo['public_cert']),
                    ],
                ]
            ],
            'logger' => [
                'enable' => true,
                'file' => base_path(false).'/runtime/logs/wxpay-batches-'.date('Y-m-d').'.log',
                'level' => 'info', // 建议生产环境等级调整为 info，开发环境为 debug
                'type' => 'single', // optional, 可选 daily.
                'max_file' => 30, // optional, 当 type 为 daily 时有效，默认 30 天
            ]
        ]);

        // $scene_report_infos = explode('|', getenv('WECHAT_PAY_TRANSFER_SCENE_REPORT_INFOS'));
        $result = Pay::wechat()->transfer([
            'notify_url' => getenv('API_HOST').'/api/order/batches/notify/'.$paymentInfo['order_sn'].'/'.$prize_sn,
            'appid' => sysconfig('wechat', 'miniapp_appid'),
            '_action' => 'mch_transfer',
            'out_bill_no' => $prize_sn,
            'transfer_scene_id' => '1000', // getenv('WECHAT_PAY_TRANSFER_SCENE_ID'),
            'openid' => $paymentInfo['openid'],
            'user_recv_perception' => '现金奖励', // getenv('WECHAT_PAY_USER_RECV_PERCEPTION'),
            'transfer_amount' => $transfer_amount,
            'transfer_remark' => $transfer_remark,
            /*'transfer_scene_report_infos' => [
                ['info_type' => str_replace(" ", "", explode(':', $scene_report_infos[0])[0]), 'info_content' => str_replace(" ", "", explode(':', $scene_report_infos[0])[1])],
                ['info_type' => str_replace(" ", "", explode(':', $scene_report_infos[1])[0]), 'info_content' => str_replace(" ", "", explode(':', $scene_report_infos[1])[1])],
            ],*/
            'transfer_scene_report_infos' => [
                ['info_type' => '活动名称', 'info_content' => $paymentInfo['activity_title']],
                ['info_type' => '奖励说明', 'info_content' => $prize_name],
            ],
        ]);
        return $result;
    }

    /**
     * 转账回调
     * @param Request $request
     * @param $orderSN
     * @param $disburseSN
     * @return ResponseInterface
     * @throws \Yansongda\Artful\Exception\ContainerException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function batchesNotify(Request $request, $orderSN, $disburseSN)
    {
        $paymentInfo = Db::name('order')
            ->alias('order')
            ->join('user', 'order.user_id = user.id')
            ->join('activity', 'order.activity_id = activity.id')
            ->join('payment_account account', 'activity.recom_payment_id = account.id')
            ->field('user.openid, account.mchid, account.appsecret, account.pemcert, account.pemkey, account.public_cert, account.public_cert_id')
            ->field('order.order_sn, activity.activity_title')
            ->where(['order.order_sn' => $orderSN])
            ->find();

        Pay::config([
            'wechat' => [
                'default' => [
                    // 「必填」商户号，服务商模式下为服务商商户号
                    'mch_id' => $paymentInfo['mchid'],
                    // 「必填」v3 商户秘钥
                    'mch_secret_key' => $paymentInfo['appsecret'],
                    // 「必填」商户私钥 字符串或路径
                    'mch_secret_cert' => url2tempFile($paymentInfo['pemkey']),
                    // 「必填」商户公钥证书路径
                    'mch_public_cert_path' => url2tempFile($paymentInfo['pemcert']),
                    // 「选填」小程序 的 app_id
                    'mini_app_id' => sysconfig('wechat', 'miniapp_appid'),
                    // 「选填」（适用于 2024-11 及之前开通微信支付的老商户）微信平台公钥证书路径，强烈建议 php-fpm 模式下配置此参数
                    // 「必填」微信支付公钥证书路径，key 填写形如 PUB_KEY_ID_0000000000000024101100397200000006 的公钥id，见 https://pay.weixin.qq.com/doc/v3/merchant/4013053249
                    'wechat_public_cert_path' => [
                        $paymentInfo['public_cert_id'] => url2tempFile($paymentInfo['public_cert']),
                    ],
                ]
            ]
        ]);

        try {
            $result = Pay::wechat()->callback();

            Log::info('['.date('Y-m-d H:i:s').'] wxpay-batches-notify');
            Log::info(json_encode($result, JSON_UNESCAPED_UNICODE));

            if ($result['event_type'] == 'MCHTRANSFER.BILL.FINISHED') {
                Db::name('payment_disburse')->where(['disburse_sn' => $disburseSN])->update(['status' => 1, 'disburse_time' => date('Y-m-d H:i:s')]);
            }
            return Pay::wechat()->success();
        } catch (\Exception $e) {
            return Pay::wechat()->error();
        }
    }

    /**
     * 退款
     * @param $activity_id
     * @param $user_id
     * @return true
     * @throws \Exception
     */
    public function refund($activity_id, $user_id)
    {
        // 退款
        try {
            $paymentInfo = Db::name('order')
                ->alias('order')
                ->join('user', 'order.user_id = user.id')
                ->join('activity', 'order.activity_id = activity.id')
                ->join('payment_account account', 'activity.activity_payment_id = account.id')
                ->field('user.openid, account.mchid, account.appsecret, account.pemcert, account.pemkey')
                ->field('order.id as order_id, order.activity_id, order.total_price, order.order_sn')
                ->where(['order.user_id' => $user_id, 'order.activity_id' => $activity_id])
                ->find();

            Pay::config([
                'wechat' => [
                    'default' => [
                        // 「必填」商户号，服务商模式下为服务商商户号
                        'mch_id' => $paymentInfo['mchid'],
                        // 「必填」v3 商户秘钥
                        'mch_secret_key' => $paymentInfo['appsecret'],
                        // 「必填」商户私钥 字符串或路径
                        'mch_secret_cert' => url2tempFile($paymentInfo['pemkey']),
                        // 「必填」商户公钥证书路径
                        'mch_public_cert_path' => url2tempFile($paymentInfo['pemcert']),
                        // 「选填」小程序 的 app_id
                        'mini_app_id' => sysconfig('wechat', 'miniapp_appid'),
                        // 「选填」（适用于 2024-11 及之前开通微信支付的老商户）微信平台公钥证书路径，强烈建议 php-fpm 模式下配置此参数
                        // 「必填」微信支付公钥证书路径，key 填写形如 PUB_KEY_ID_0000000000000024101100397200000006 的公钥id，见 https://pay.weixin.qq.com/doc/v3/merchant/4013053249
                        'wechat_public_cert_path' => [
                            $paymentInfo['public_cert_id'] => url2tempFile($paymentInfo['public_cert']),
                        ],
                    ]
                ],
                'logger' => [ // optional
                    'enable' => true,
                    'file' => base_path().'/runtime/logs/wxpay-refund-'.date('Y-m-d').'.log',
                    'level' => 'info', // 建议生产环境等级调整为 info，开发环境为 debug
                    'type' => 'single', // optional, 可选 daily.
                    'max_file' => 30, // optional, 当 type 为 daily 时有效，默认 30 天
                ]
            ]);
            $order = [
                'notify_url' => getenv('API_HOST').'/api/order/refund/notify/'.$paymentInfo['order_sn'],
                'out_trade_no' => $paymentInfo['order_sn'],
                'out_refund_no' => $paymentInfo['order_sn'].'REFUND'.date('YmdHis'),
                'amount' => [
                    'refund' => $paymentInfo['total_price'] * 100,
                    'total' => $paymentInfo['total_price'] * 100,
                    'currency' => 'CNY',
                ],
                '_action' => 'mini', // 小程序退款
            ];
            Pay::wechat()->refund($order);
            return true;
        } catch (\Exception $e) {
            throw new \Exception($e->response->message ?? $e->getMessage());
        }
    }

    /**
     * 退款回调
     * @param Request $request
     * @param $orderSN
     * @param $refundSN
     * @return ResponseInterface
     * @throws \Yansongda\Artful\Exception\ContainerException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function refundNotify(Request $request, $orderSN)
    {
        $paymentInfo = Db::name('order')
            ->alias('order')
            ->join('user', 'order.user_id = user.id')
            ->join('activity', 'order.activity_id = activity.id')
            ->join('payment_account account', 'activity.recom_payment_id = account.id')
            ->field('user.openid, account.mchid, account.appsecret, account.pemcert, account.pemkey, account.public_cert, account.public_cert_id')
            ->field('order.order_sn, activity.activity_title')
            ->where(['order.order_sn' => $orderSN])
            ->find();

        Pay::config([
            'wechat' => [
                'default' => [
                    // 「必填」商户号，服务商模式下为服务商商户号
                    'mch_id' => $paymentInfo['mchid'],
                    // 「必填」v3 商户秘钥
                    'mch_secret_key' => $paymentInfo['appsecret'],
                    // 「必填」商户私钥 字符串或路径
                    'mch_secret_cert' => url2tempFile($paymentInfo['pemkey']),
                    // 「必填」商户公钥证书路径
                    'mch_public_cert_path' => url2tempFile($paymentInfo['pemcert']),
                    // 「选填」小程序 的 app_id
                    'mini_app_id' => sysconfig('wechat', 'miniapp_appid'),
                    // 「选填」（适用于 2024-11 及之前开通微信支付的老商户）微信平台公钥证书路径，强烈建议 php-fpm 模式下配置此参数
                    // 「必填」微信支付公钥证书路径，key 填写形如 PUB_KEY_ID_0000000000000024101100397200000006 的公钥id，见 https://pay.weixin.qq.com/doc/v3/merchant/4013053249
                    'wechat_public_cert_path' => [
                        $paymentInfo['public_cert_id'] => url2tempFile($paymentInfo['public_cert']),
                    ],
                ]
            ]
        ]);

        try {
            $result = Pay::wechat()->callback();

            Log::info('['.date('Y-m-d H:i:s').'] wxpay-refund-notify');
            Log::info(json_encode($result, JSON_UNESCAPED_UNICODE));

            if ($result['event_type'] == 'REFUND.SUCCESS') {
                Db::name('order')->where(['order_sn' => $orderSN])->update(['refund_status' => 1, 'refund_no' => $result['resource']['ciphertext']['out_refund_no'], 'refund_time' => date('Y-m-d H:i:s')]);
            }
            return Pay::wechat()->success();
        } catch (\Exception $e) {
            return Pay::wechat()->error();
        }
    }
}
